﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Brainee.Search
{
  /// <summary>
  /// Represents a solution of a problem.
  /// </summary>
  public class PathSolution : IEnumerable<ISearchState>
  {
#region Empty solution

    private class EmptySolution : PathSolution
    {
      public EmptySolution ()
        : base (null)
      {
      }
    }

#endregion
#region Fields

    /// <summary>
    /// Represents an object that should be returned when a solution of
    /// a problem does not exists.
    /// </summary>
    public static readonly PathSolution None = new EmptySolution ();

    /// <summary>
    /// Represents an object that should be returned when the search has 
    /// been interrupted by a depth limit constraint.
    /// </summary>
    public static readonly PathSolution Cutoff = new EmptySolution ();

    private List<ISearchState> _states = new List<ISearchState> ();

#endregion
#region Construction

    /// <summary>
    /// Create a new PathSolution instance from the a goal state of a search algorithm
    /// </summary>
    /// <param name="goalState"></param>
    public PathSolution (ISearchState goalState)
    {
      ISearchState state = goalState;
      while (state != null)
      {
        _states.Insert (0, state);
        state = state.Parent;
      }
    }

#endregion
#region Properties

    public IEnumerable<IAction> Actions { get { return _states.Skip(1).Select (n => n.Action); } }
    public IEnumerable<IState> States { get { return _states.Select (n => n.State); } }
    public double PathCost { get { return _states.Last ().PathCost; } }

#endregion
#region IEnumerable<ISearchState> Members

    public IEnumerator<ISearchState> GetEnumerator ()
    {
      return _states.GetEnumerator ();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
    {
      return ((System.Collections.IEnumerable)_states).GetEnumerator ();
    }

#endregion
  }
}
